#include <linux/uaccess.h>
#include <linux/init.h>
#include <linux/kernel_stat.h>
#include <linux/platform_device.h>
#include <linux/kobject.h>
#include <linux/sysfs.h>
#include <net/neighbour.h>
#include <net/arp.h>
#include <linux/jiffies.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/socket.h>
#include <linux/errno.h>
#include <linux/fcntl.h>
#include <linux/in.h>

#include <asm/uaccess.h>
#include <asm/io.h>

#include <linux/inet.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/ethtool.h>
#include <net/sock.h>
#include <net/checksum.h>
#include <linux/if_ether.h>	/* For the statistics structure. */
#include <linux/if_arp.h>	/* For ARPHRD_ETHER */
#include <linux/ip.h>
#include <linux/if.h>
#include <linux/tcp.h>
#include <linux/percpu.h>
#include <net/net_namespace.h>
#include <linux/u64_stats_sync.h>

#define NETIUCV_MTU_DEFAULT 1500

/**
 * /sys/class/net/eth0/flags
 *  sudo  arp-scan -I eth0  --localnet
 *  the hardware address is used to generate correct Ethernet headers
 *  before the packet is handed over to the driver for transmission.
 *
 *  dev_alloc_skb
 *
 *
 */

struct net_device *mynet_device;

struct mypriv {

};

/*
 * Interface API for upper network layers
 */

/**
 * Open an interface.
 * Called from generic network layer when ifconfig up is run.
 *
 * @param dev Pointer to interface struct.
 *
 * @return 0 on success, -ERRNO on failure. (Never fails.)
 */
static int netiucv_open(struct net_device *dev) {
	memcpy(dev->dev_addr, "\0andy001", ETH_ALEN);
	netif_start_queue(dev);
	return 0;
}

/**
 * Close an interface.
 * Called from generic network layer when ifconfig down is run.
 *
 * @param dev Pointer to interface struct.
 *
 * @return 0 on success, -ERRNO on failure. (Never fails.)
 */
static int netiucv_close(struct net_device *dev) {
	netif_stop_queue(dev);
	return 0;
}

/**
 * netiucv_stats
 * @dev: Pointer to interface struct.
 *
 * Returns interface statistics of a device.
 *
 * Returns pointer to stats struct of this interface.
 */

//static struct net_device_stats *netiucv_stats (struct net_device * dev)
//{
//	struct netiucv_priv *priv = netdev_priv(dev);
//	return &priv->stats;
//}

const struct net_device_ops mynetdev_ops = { .ndo_open = netiucv_open,
		.ndo_stop = netiucv_close,
//		.ndo_get_stats = netiucv_stats,
//		.ndo_start_xmit = netiucv_tx,
//		.ndo_change_mtu = netiucv_change_mtu,

		};

void mysetup(struct net_device *dev) {
	int k, j;
		char hbuffer[30];
	unsigned char  *ptr;
	dev->mtu = NETIUCV_MTU_DEFAULT;
	dev->netdev_ops = &mynetdev_ops;
	dev->addr_len = 6;
	dev->type = ARPHRD_SLIP;
	dev->flags = IFF_NOARP|IFF_BROADCAST|IFF_MULTICAST;

	ptr =dev->perm_addr;
	*(ptr++)=0xa1;
	*(ptr++)=0xa1;
	*(ptr++)=0xa2;
	*(ptr++)=0xa1;
	*(ptr++)=0xa1;
	*(ptr++)=0xa1;



//	for (k = 0, j = 0; k < 30 - 3 && j < dev->addr_len; j++) {
//			hbuffer[k++] = hex_asc_hi(dev->perm_addr[j]);
//			hbuffer[k++] = hex_asc_lo(dev->perm_addr[j]);
//			hbuffer[k++] = ':';
//		}
//		if (k != 0)
//			--k;
//		hbuffer[k] = 0;
//		pr_info("mac: %s\n", hbuffer);















}

int myprobe(struct platform_device *pdev) {
	int ret;
	mynet_device = alloc_netdev(sizeof(struct mypriv), "mynetdev%d",
			NET_NAME_UNKNOWN, mysetup);
	if (!mynet_device)
		return -1;
	ret = register_netdev(mynet_device);
	if (ret) {
		pr_info("register_netdev fails: %d\n", ret);
		return ret;
	}
	pr_info("myplatformdriver myprobe \n");

	pr_info("hex_asc a0  %c \n",hex_asc[0x9]);

	return 0;
}

int myremove(struct platform_device *pdev) {
	pr_info("myplatformdriver myremove \n");
	unregister_netdev(mynet_device);
	free_netdev(mynet_device);
	return 0;
}

struct of_device_id my_of_match_table =
		{ .compatible = "my_platform_device_003", };

struct platform_driver my_platform_driver = { .driver =
		{ .of_match_table = &my_of_match_table, .name = "my-platform-driver",
				.owner = THIS_MODULE, }, .probe = myprobe, .remove = myremove, };

module_platform_driver(my_platform_driver);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Andy");
MODULE_DESCRIPTION("andy one-key driver");
MODULE_ALIAS("one-key");
